Micron Document
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| SparkN0de-git | SparkN0de |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Node / ReticulumProjects / MeshChatX.git / files / meshchatx / src / frontend / js / nomadFavouritesLayoutStore.js

Displaying Raw • Download


meshchatx/src/frontend/js/nomadFavouritesLayoutStore.js c0b0ddffd735a0d007c1be9a5e8563ec42fdafc0 (c0b0ddff) Text, 9.48 KB

T8b949e// SPDX-License-Identifier: 0BSD

Tff7b72export Tff7b72const Te6edf3NOMAD_FAVOURITES_LAYOUT_KEY Tff7b72= Ta5d6ff"meshchat.nomadnet.favourites.layout"Tb4b4b4;
Tff7b72export Tff7b72const Te6edf3NOMAD_FAVOURITES_LEGACY_ORDER_KEY Tff7b72= Ta5d6ff"meshchat.nomadnet.favourites"Tb4b4b4;

T8b949e// Keep in sync with meshchatx/src/backend/favourites_layout.py
Tff7b72export Tff7b72const Te6edf3MAX_SECTIONS Tff7b72= T79c0ff64Tb4b4b4;
Tff7b72export Tff7b72const Te6edf3MAX_SECTION_ID_LEN Tff7b72= T79c0ff64Tb4b4b4;
Tff7b72export Tff7b72const Te6edf3MAX_SECTION_NAME_LEN Tff7b72= T79c0ff128Tb4b4b4;
Tff7b72export Tff7b72const Te6edf3MAX_HASHES_PER_SECTION Tff7b72= T79c0ff2000Tb4b4b4;
Tff7b72export Tff7b72const Te6edf3MAX_TOTAL_HASHES Tff7b72= T79c0ff4000Tb4b4b4;
Tff7b72export Tff7b72const Te6edf3MAX_HASH_LEN Tff7b72= T79c0ff64Tb4b4b4;

Tff7b72const Te6edf3FORBIDDEN_SECTION_IDS Tff7b72= Tff7b72new Tffa657SetTb4b4b4(Tb4b4b4[Ta5d6ff"__proto__"Tb4b4b4, Ta5d6ff"constructor"Tb4b4b4, Ta5d6ff"prototype"Tb4b4b4]Tb4b4b4)Tb4b4b4;

T8b949e/**
* @param {unknown} value
* @param {number} maxLen
* @returns {string}
*/
Tff7b72function Te6edf3clipStrTb4b4b4(Te6edf3valueTb4b4b4, Te6edf3maxLenTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72typeof Te6edf3value Tff7b72!== Ta5d6ff"string"Tb4b4b4) Tb4b4b4{
Tff7b72return Ta5d6ff""Tb4b4b4;
Tb4b4b4}
Tff7b72return Te6edf3valueTb4b4b4.Te6edf3length Tff7b72<= Te6edf3maxLen Tff7b72? Te6edf3value Tff7b72: Te6edf3valueTb4b4b4.Te6edf3sliceTb4b4b4(T79c0ff0Tb4b4b4, Te6edf3maxLenTb4b4b4)Tb4b4b4;
Tb4b4b4}

T8b949e/**
* @param {unknown} layout
* @returns {{sections: object[], sectionOrder: string[], favouritesBySection: Record<string, string[]>}|null}
*/
Tff7b72export Tff7b72function Te6edf3normalizeNomadFavouritesLayoutTb4b4b4(Te6edf3layoutTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3layout Tff7b72|| Tff7b72typeof Te6edf3layout Tff7b72!== Ta5d6ff"object" Tff7b72|| Tffa657ArrayTb4b4b4.Te6edf3isArrayTb4b4b4(Te6edf3layoutTb4b4b4) Tff7b72|| Tff7b72!Tffa657ArrayTb4b4b4.Te6edf3isArrayTb4b4b4(Te6edf3layoutTb4b4b4.Te6edf3sectionsTb4b4b4)Tb4b4b4) Tb4b4b4{
Tff7b72return Tff7b72nullTb4b4b4;
Tb4b4b4}
Tff7b72const Te6edf3favouritesBySection Tff7b72=
Te6edf3layoutTb4b4b4.Te6edf3favouritesBySection Tff7b72&&
Tff7b72typeof Te6edf3layoutTb4b4b4.Te6edf3favouritesBySection Tff7b72=== Ta5d6ff"object" Tff7b72&&
Tff7b72!Tffa657ArrayTb4b4b4.Te6edf3isArrayTb4b4b4(Te6edf3layoutTb4b4b4.Te6edf3favouritesBySectionTb4b4b4)
Tff7b72? Te6edf3layoutTb4b4b4.Te6edf3favouritesBySection
Tff7b72: Tb4b4b4{Tb4b4b4}Tb4b4b4;
Tff7b72const Te6edf3sections Tff7b72= Tb4b4b4[Tb4b4b4]Tb4b4b4;
Tff7b72const Te6edf3sectionIds Tff7b72= Tff7b72new Tffa657SetTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72for Tb4b4b4(Tff7b72const Te6edf3section Tff7b72of Te6edf3layoutTb4b4b4.Te6edf3sectionsTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3sectionsTb4b4b4.Te6edf3length Tff7b72>= Te6edf3MAX_SECTIONSTb4b4b4) Tb4b4b4{
Tff7b72breakTb4b4b4;
Tb4b4b4}
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3section Tff7b72|| Tff7b72typeof Te6edf3section Tff7b72!== Ta5d6ff"object" Tff7b72|| Tffa657ArrayTb4b4b4.Te6edf3isArrayTb4b4b4(Te6edf3sectionTb4b4b4)Tb4b4b4) Tb4b4b4{
Tff7b72continueTb4b4b4;
Tb4b4b4}
Tff7b72if Tb4b4b4(Tff7b72typeof Te6edf3sectionTb4b4b4.Te6edf3id Tff7b72!== Ta5d6ff"string"Tb4b4b4) Tb4b4b4{
Tff7b72continueTb4b4b4;
Tb4b4b4}
Tff7b72const Te6edf3sectionId Tff7b72= Te6edf3sectionTb4b4b4.Te6edf3idTb4b4b4.Te6edf3trimTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(
Tff7b72!Te6edf3sectionId Tff7b72||
Te6edf3sectionIdTb4b4b4.Te6edf3length Tff7b72> Te6edf3MAX_SECTION_ID_LEN Tff7b72||
Te6edf3sectionIdsTb4b4b4.Te6edf3hasTb4b4b4(Te6edf3sectionIdTb4b4b4) Tff7b72||
Te6edf3FORBIDDEN_SECTION_IDSTb4b4b4.Te6edf3hasTb4b4b4(Te6edf3sectionIdTb4b4b4)
Tb4b4b4) Tb4b4b4{
Tff7b72continueTb4b4b4;
Tb4b4b4}
Te6edf3sectionIdsTb4b4b4.Te6edf3addTb4b4b4(Te6edf3sectionIdTb4b4b4)Tb4b4b4;
Te6edf3sectionsTb4b4b4.Te6edf3pushTb4b4b4(Tb4b4b4{
Te6edf3idTff7b72: Te6edf3sectionIdTb4b4b4,
Te6edf3nameTff7b72: Te6edf3clipStrTb4b4b4(Te6edf3sectionTb4b4b4.Te6edf3nameTb4b4b4, Te6edf3MAX_SECTION_NAME_LENTb4b4b4)Tb4b4b4,
Te6edf3collapsedTff7b72: Te6edf3sectionTb4b4b4.Te6edf3collapsed Tff7b72=== Tff7b72trueTb4b4b4,
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3sectionsTb4b4b4.Te6edf3length Tff7b72=== T79c0ff0Tb4b4b4) Tb4b4b4{
Tff7b72return Tff7b72nullTb4b4b4;
Tb4b4b4}
Tff7b72const Te6edf3sectionOrder Tff7b72= Tb4b4b4[Tb4b4b4]Tb4b4b4;
Tff7b72if Tb4b4b4(Tffa657ArrayTb4b4b4.Te6edf3isArrayTb4b4b4(Te6edf3layoutTb4b4b4.Te6edf3sectionOrderTb4b4b4)Tb4b4b4) Tb4b4b4{
Tff7b72for Tb4b4b4(Tff7b72const Te6edf3sid Tff7b72of Te6edf3layoutTb4b4b4.Te6edf3sectionOrderTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72typeof Te6edf3sid Tff7b72!== Ta5d6ff"string"Tb4b4b4) Tb4b4b4{
Tff7b72continueTb4b4b4;
Tb4b4b4}
Tff7b72const Te6edf3id Tff7b72= Te6edf3sidTb4b4b4.Te6edf3trimTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3sectionIdsTb4b4b4.Te6edf3hasTb4b4b4(Te6edf3idTb4b4b4) Tff7b72&& Tff7b72!Te6edf3sectionOrderTb4b4b4.Te6edf3includesTb4b4b4(Te6edf3idTb4b4b4)Tb4b4b4) Tb4b4b4{
Te6edf3sectionOrderTb4b4b4.Te6edf3pushTb4b4b4(Te6edf3idTb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3sectionOrderTb4b4b4.Te6edf3length Tff7b72>= Te6edf3MAX_SECTIONSTb4b4b4) Tb4b4b4{
Tff7b72breakTb4b4b4;
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tff7b72for Tb4b4b4(Tff7b72const Te6edf3section Tff7b72of Te6edf3sectionsTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3sectionOrderTb4b4b4.Te6edf3includesTb4b4b4(Te6edf3sectionTb4b4b4.Te6edf3idTb4b4b4)Tb4b4b4) Tb4b4b4{
Te6edf3sectionOrderTb4b4b4.Te6edf3pushTb4b4b4(Te6edf3sectionTb4b4b4.Te6edf3idTb4b4b4)Tb4b4b4;
Tb4b4b4}
Tb4b4b4}
Tff7b72const Te6edf3sanitizedMap Tff7b72= Tffa657ObjectTb4b4b4.Te6edf3createTb4b4b4(Tff7b72nullTb4b4b4)Tb4b4b4;
Tff7b72let Te6edf3totalHashes Tff7b72= T79c0ff0Tb4b4b4;
Tff7b72for Tb4b4b4(Tff7b72const Te6edf3key Tff7b72of Tffa657ObjectTb4b4b4.Te6edf3keysTb4b4b4(Te6edf3favouritesBySectionTb4b4b4)Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3sectionIdsTb4b4b4.Te6edf3hasTb4b4b4(Te6edf3keyTb4b4b4) Tff7b72|| Te6edf3FORBIDDEN_SECTION_IDSTb4b4b4.Te6edf3hasTb4b4b4(Te6edf3keyTb4b4b4)Tb4b4b4) Tb4b4b4{
Tff7b72continueTb4b4b4;
Tb4b4b4}
Tff7b72const Te6edf3arr Tff7b72= Te6edf3favouritesBySectionTb4b4b4[Te6edf3keyTb4b4b4]Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Tffa657ArrayTb4b4b4.Te6edf3isArrayTb4b4b4(Te6edf3arrTb4b4b4)Tb4b4b4) Tb4b4b4{
Tff7b72continueTb4b4b4;
Tb4b4b4}
Tff7b72const Te6edf3hashes Tff7b72= Tb4b4b4[Tb4b4b4]Tb4b4b4;
Tff7b72const Te6edf3seen Tff7b72= Tff7b72new Tffa657SetTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72for Tb4b4b4(Tff7b72const Te6edf3item Tff7b72of Te6edf3arrTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3totalHashes Tff7b72>= Te6edf3MAX_TOTAL_HASHES Tff7b72|| Te6edf3hashesTb4b4b4.Te6edf3length Tff7b72>= Te6edf3MAX_HASHES_PER_SECTIONTb4b4b4) Tb4b4b4{
Tff7b72breakTb4b4b4;
Tb4b4b4}
Tff7b72if Tb4b4b4(Tff7b72typeof Te6edf3item Tff7b72!== Ta5d6ff"string"Tb4b4b4) Tb4b4b4{
Tff7b72continueTb4b4b4;
Tb4b4b4}
Tff7b72const Te6edf3h Tff7b72= Te6edf3itemTb4b4b4.Te6edf3trimTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3h Tff7b72|| Te6edf3hTb4b4b4.Te6edf3length Tff7b72> Te6edf3MAX_HASH_LEN Tff7b72|| Te6edf3seenTb4b4b4.Te6edf3hasTb4b4b4(Te6edf3hTb4b4b4)Tb4b4b4) Tb4b4b4{
Tff7b72continueTb4b4b4;
Tb4b4b4}
Te6edf3seenTb4b4b4.Te6edf3addTb4b4b4(Te6edf3hTb4b4b4)Tb4b4b4;
Te6edf3hashesTb4b4b4.Te6edf3pushTb4b4b4(Te6edf3hTb4b4b4)Tb4b4b4;
Te6edf3totalHashes Tff7b72+= T79c0ff1Tb4b4b4;
Tb4b4b4}
Te6edf3sanitizedMapTb4b4b4[Te6edf3keyTb4b4b4] Tff7b72= Te6edf3hashesTb4b4b4;
Tb4b4b4}
Tff7b72for Tb4b4b4(Tff7b72const Te6edf3section Tff7b72of Te6edf3sectionsTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Tffa657ObjectTb4b4b4.Te6edf3prototypeTb4b4b4.Te6edf3hasOwnPropertyTb4b4b4.Te6edf3callTb4b4b4(Te6edf3sanitizedMapTb4b4b4, Te6edf3sectionTb4b4b4.Te6edf3idTb4b4b4)Tb4b4b4) Tb4b4b4{
Te6edf3sanitizedMapTb4b4b4[Te6edf3sectionTb4b4b4.Te6edf3idTb4b4b4] Tff7b72= Tb4b4b4[Tb4b4b4]Tb4b4b4;
Tb4b4b4}
Tb4b4b4}
Tff7b72return Tb4b4b4{ Te6edf3sectionsTb4b4b4, Te6edf3sectionOrderTb4b4b4, Te6edf3favouritesBySectionTff7b72: Te6edf3sanitizedMap Tb4b4b4}Tb4b4b4;
Tb4b4b4}

T8b949e/**
* Stable JSON for equality checks (avoids unnecessary PUTs).
* @param {object|null} layout
* @returns {string}
*/
Tff7b72export Tff7b72function Te6edf3serializeNomadFavouritesLayoutTb4b4b4(Te6edf3layoutTb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3normalized Tff7b72= Te6edf3normalizeNomadFavouritesLayoutTb4b4b4(Te6edf3layoutTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3normalizedTb4b4b4) Tb4b4b4{
Tff7b72return Ta5d6ff""Tb4b4b4;
Tb4b4b4}
Tff7b72return Tffa657JSONTb4b4b4.Te6edf3stringifyTb4b4b4(Te6edf3normalizedTb4b4b4)Tb4b4b4;
Tb4b4b4}

Tff7b72export Tff7b72function Te6edf3readLocalNomadFavouritesLayoutTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72try Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72typeof Tffa657window Tff7b72=== Ta5d6ff"undefined" Tff7b72|| Tff7b72!Tffa657windowTb4b4b4.Te6edf3localStorageTb4b4b4) Tb4b4b4{
Tff7b72return Tff7b72nullTb4b4b4;
Tb4b4b4}
Tff7b72const Te6edf3stored Tff7b72= Tffa657windowTb4b4b4.Te6edf3localStorageTb4b4b4.Te6edf3getItemTb4b4b4(Te6edf3NOMAD_FAVOURITES_LAYOUT_KEYTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3storedTb4b4b4) Tb4b4b4{
Tff7b72return Te6edf3normalizeNomadFavouritesLayoutTb4b4b4(Tffa657JSONTb4b4b4.Te6edf3parseTb4b4b4(Te6edf3storedTb4b4b4)Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72const Te6edf3legacyOrder Tff7b72= Tffa657windowTb4b4b4.Te6edf3localStorageTb4b4b4.Te6edf3getItemTb4b4b4(Te6edf3NOMAD_FAVOURITES_LEGACY_ORDER_KEYTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3legacyOrderTb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3parsedOrder Tff7b72= Tffa657JSONTb4b4b4.Te6edf3parseTb4b4b4(Te6edf3legacyOrderTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tffa657ArrayTb4b4b4.Te6edf3isArrayTb4b4b4(Te6edf3parsedOrderTb4b4b4)Tb4b4b4) Tb4b4b4{
Tff7b72return Te6edf3normalizeNomadFavouritesLayoutTb4b4b4(Tb4b4b4{
Te6edf3sectionsTff7b72: Tb4b4b4[Tb4b4b4{ Te6edf3idTff7b72: Ta5d6ff"default"Tb4b4b4, Te6edf3nameTff7b72: Ta5d6ff"Favourites"Tb4b4b4, Te6edf3collapsedTff7b72: Tff7b72false Tb4b4b4}Tb4b4b4]Tb4b4b4,
Te6edf3sectionOrderTff7b72: Tb4b4b4[Ta5d6ff"default"Tb4b4b4]Tb4b4b4,
Te6edf3favouritesBySectionTff7b72: Tb4b4b4{ Tff7b72defaultTff7b72: Te6edf3parsedOrderTb4b4b4.Te6edf3filterTb4b4b4(Tb4b4b4(Te6edf3hTb4b4b4) Tb4b4b4=> Tff7b72typeof Te6edf3h Tff7b72=== Ta5d6ff"string"Tb4b4b4) Tb4b4b4}Tb4b4b4,
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tb4b4b4}
Tb4b4b4} Tff7b72catch Tb4b4b4{
T8b949e// ignore
Tb4b4b4}
Tff7b72return Tff7b72nullTb4b4b4;
Tb4b4b4}

Tff7b72function Te6edf3writeLocalLayoutTb4b4b4(Te6edf3layoutTb4b4b4) Tb4b4b4{
Tff7b72try Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72typeof Tffa657window Tff7b72=== Ta5d6ff"undefined" Tff7b72|| Tff7b72!Tffa657windowTb4b4b4.Te6edf3localStorageTb4b4b4) Tb4b4b4{
Tff7b72returnTb4b4b4;
Tb4b4b4}
Tff7b72const Te6edf3normalized Tff7b72= Te6edf3normalizeNomadFavouritesLayoutTb4b4b4(Te6edf3layoutTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3normalizedTb4b4b4) Tb4b4b4{
Tff7b72returnTb4b4b4;
Tb4b4b4}
Tffa657windowTb4b4b4.Te6edf3localStorageTb4b4b4.Te6edf3setItemTb4b4b4(Te6edf3NOMAD_FAVOURITES_LAYOUT_KEYTb4b4b4, Tffa657JSONTb4b4b4.Te6edf3stringifyTb4b4b4(Te6edf3normalizedTb4b4b4)Tb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72catch Tb4b4b4{
T8b949e// ignore
Tb4b4b4}
Tb4b4b4}

Tff7b72let Te6edf3saveInFlight Tff7b72= Tff7b72nullTb4b4b4;
Tff7b72let Te6edf3pendingSaveLayout Tff7b72= Tff7b72nullTb4b4b4;
Tff7b72let Te6edf3lastSavedSerialized Tff7b72= Ta5d6ff""Tb4b4b4;

T8b949e/**
* Load favourite section layout from the identity DB, migrating localStorage once.
* @param {*} api window.api-like client
* @returns {Promise<object|null>}
*/
Tff7b72export Tff7b72async Tff7b72function Te6edf3loadNomadFavouritesLayoutTb4b4b4(Te6edf3apiTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3apiTff7b72?Tb4b4b4.Te6edf3getTb4b4b4) Tb4b4b4{
Tff7b72return Te6edf3readLocalNomadFavouritesLayoutTb4b4b4(Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72try Tb4b4b4{
Tff7b72const Te6edf3response Tff7b72= Tff7b72await Te6edf3apiTb4b4b4.Te6edf3getTb4b4b4(Ta5d6ff"/api/v1/favourites/layout"Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3remote Tff7b72= Te6edf3normalizeNomadFavouritesLayoutTb4b4b4(Te6edf3responseTff7b72?Tb4b4b4.Te6edf3dataTff7b72?Tb4b4b4.Te6edf3layoutTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3remoteTb4b4b4) Tb4b4b4{
Te6edf3writeLocalLayoutTb4b4b4(Te6edf3remoteTb4b4b4)Tb4b4b4;
Te6edf3lastSavedSerialized Tff7b72= Te6edf3serializeNomadFavouritesLayoutTb4b4b4(Te6edf3remoteTb4b4b4)Tb4b4b4;
Tff7b72return Te6edf3remoteTb4b4b4;
Tb4b4b4}
Tb4b4b4} Tff7b72catch Tb4b4b4{
T8b949e// fall through to local
Tb4b4b4}
Tff7b72const Te6edf3local Tff7b72= Te6edf3readLocalNomadFavouritesLayoutTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3local Tff7b72&& Te6edf3apiTff7b72?Tb4b4b4.Te6edf3putTb4b4b4) Tb4b4b4{
Tff7b72try Tb4b4b4{
Tff7b72const Te6edf3response Tff7b72= Tff7b72await Te6edf3apiTb4b4b4.Te6edf3putTb4b4b4(Ta5d6ff"/api/v1/favourites/layout"Tb4b4b4, Tb4b4b4{ Te6edf3layoutTff7b72: Te6edf3local Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3saved Tff7b72= Te6edf3normalizeNomadFavouritesLayoutTb4b4b4(Te6edf3responseTff7b72?Tb4b4b4.Te6edf3dataTff7b72?Tb4b4b4.Te6edf3layoutTb4b4b4) Tff7b72|| Te6edf3localTb4b4b4;
Te6edf3writeLocalLayoutTb4b4b4(Te6edf3savedTb4b4b4)Tb4b4b4;
Te6edf3lastSavedSerialized Tff7b72= Te6edf3serializeNomadFavouritesLayoutTb4b4b4(Te6edf3savedTb4b4b4)Tb4b4b4;
Tff7b72try Tb4b4b4{
Tffa657windowTb4b4b4.Te6edf3localStorageTff7b72?Tb4b4b4.Te6edf3removeItemTb4b4b4(Te6edf3NOMAD_FAVOURITES_LEGACY_ORDER_KEYTb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72catch Tb4b4b4{
T8b949e// ignore
Tb4b4b4}
Tff7b72return Te6edf3savedTb4b4b4;
Tb4b4b4} Tff7b72catch Tb4b4b4{
Tff7b72return Te6edf3localTb4b4b4;
Tb4b4b4}
Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3localTb4b4b4) Tb4b4b4{
Te6edf3lastSavedSerialized Tff7b72= Te6edf3serializeNomadFavouritesLayoutTb4b4b4(Te6edf3localTb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72return Te6edf3localTb4b4b4;
Tb4b4b4}

Tff7b72async Tff7b72function Te6edf3flushPendingSaveTb4b4b4(Te6edf3apiTb4b4b4) Tb4b4b4{
Tff7b72while Tb4b4b4(Te6edf3pendingSaveLayoutTb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3layout Tff7b72= Te6edf3pendingSaveLayoutTb4b4b4;
Te6edf3pendingSaveLayout Tff7b72= Tff7b72nullTb4b4b4;
Tff7b72const Te6edf3serialized Tff7b72= Te6edf3serializeNomadFavouritesLayoutTb4b4b4(Te6edf3layoutTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3serialized Tff7b72|| Te6edf3serialized Tff7b72=== Te6edf3lastSavedSerializedTb4b4b4) Tb4b4b4{
Tff7b72continueTb4b4b4;
Tb4b4b4}
Tff7b72try Tb4b4b4{
Tff7b72const Te6edf3response Tff7b72= Tff7b72await Te6edf3apiTb4b4b4.Te6edf3putTb4b4b4(Ta5d6ff"/api/v1/favourites/layout"Tb4b4b4, Tb4b4b4{ Te6edf3layout Tb4b4b4}Tb4b4b4)Tb4b4b4;
T8b949e// A newer save may have arrived while this PUT was in flight, so prefer that.
Tff7b72if Tb4b4b4(Te6edf3pendingSaveLayoutTb4b4b4) Tb4b4b4{
Tff7b72continueTb4b4b4;
Tb4b4b4}
Tff7b72const Te6edf3saved Tff7b72= Te6edf3normalizeNomadFavouritesLayoutTb4b4b4(Te6edf3responseTff7b72?Tb4b4b4.Te6edf3dataTff7b72?Tb4b4b4.Te6edf3layoutTb4b4b4) Tff7b72|| Te6edf3layoutTb4b4b4;
Te6edf3writeLocalLayoutTb4b4b4(Te6edf3savedTb4b4b4)Tb4b4b4;
Te6edf3lastSavedSerialized Tff7b72= Te6edf3serializeNomadFavouritesLayoutTb4b4b4(Te6edf3savedTb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72catch Tb4b4b4{
Te6edf3writeLocalLayoutTb4b4b4(Te6edf3layoutTb4b4b4)Tb4b4b4;
T8b949e// Keep lastSavedSerialized unchanged so a later retry can push again.
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

T8b949e/**
* Persist favourite section layout to the identity DB (and local cache).
* Coalesces concurrent saves and skips no-op PUTs.
* @param {*} api window.api-like client
* @param {object} layout
* @returns {Promise<object|null>}
*/
Tff7b72export Tff7b72async Tff7b72function Te6edf3saveNomadFavouritesLayoutTb4b4b4(Te6edf3apiTb4b4b4, Te6edf3layoutTb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3normalized Tff7b72= Te6edf3normalizeNomadFavouritesLayoutTb4b4b4(Te6edf3layoutTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3normalizedTb4b4b4) Tb4b4b4{
Tff7b72return Tff7b72nullTb4b4b4;
Tb4b4b4}
Te6edf3writeLocalLayoutTb4b4b4(Te6edf3normalizedTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3apiTff7b72?Tb4b4b4.Te6edf3putTb4b4b4) Tb4b4b4{
Te6edf3lastSavedSerialized Tff7b72= Te6edf3serializeNomadFavouritesLayoutTb4b4b4(Te6edf3normalizedTb4b4b4)Tb4b4b4;
Tff7b72return Te6edf3normalizedTb4b4b4;
Tb4b4b4}
Tff7b72const Te6edf3serialized Tff7b72= Te6edf3serializeNomadFavouritesLayoutTb4b4b4(Te6edf3normalizedTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3serialized Tff7b72&& Te6edf3serialized Tff7b72=== Te6edf3lastSavedSerializedTb4b4b4) Tb4b4b4{
Tff7b72return Te6edf3normalizedTb4b4b4;
Tb4b4b4}
Te6edf3pendingSaveLayout Tff7b72= Te6edf3normalizedTb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3saveInFlightTb4b4b4) Tb4b4b4{
Te6edf3saveInFlight Tff7b72= Te6edf3flushPendingSaveTb4b4b4(Te6edf3apiTb4b4b4)Tb4b4b4.Tff7b72finallyTb4b4b4(Tb4b4b4(Tb4b4b4) Tb4b4b4=> Tb4b4b4{
Te6edf3saveInFlight Tff7b72= Tff7b72nullTb4b4b4;
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72await Te6edf3saveInFlightTb4b4b4;
Tff7b72return Te6edf3readLocalNomadFavouritesLayoutTb4b4b4(Tb4b4b4) Tff7b72|| Te6edf3normalizedTb4b4b4;
Tb4b4b4}

T8b949e/** Test helper: reset coalescing state between cases. */
Tff7b72export Tff7b72function Te6edf3_resetNomadFavouritesLayoutSaveStateForTestsTb4b4b4(Tb4b4b4) Tb4b4b4{
Te6edf3saveInFlight Tff7b72= Tff7b72nullTb4b4b4;
Te6edf3pendingSaveLayout Tff7b72= Tff7b72nullTb4b4b4;
Te6edf3lastSavedSerialized Tff7b72= Ta5d6ff""Tb4b4b4;
Tb4b4b4}


──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────